home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
prospero
/
propsero.lha
/
prospero-beta.4.2e
/
server
/
dirsrv.c
next >
Wrap
C/C++ Source or Header
|
1992-02-10
|
62KB
|
2,119 lines
/*
* Copyright (c) 1989, 1990, 1991 by the University of Washington
*
* For copying and distribution information, please see the file
* <uw-copyright.h>.
*/
#include <uw-copyright.h>
#include <netdb.h>
#include <sgtty.h>
#include <signal.h>
#include <stdio.h>
#include <strings.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <pfs.h>
#include <psite.h>
#include <plog.h>
#include <pauthent.h>
#include <pprot.h>
#include <perrno.h>
#include <pmachine.h>
#include "dirsrv.h"
#ifndef P_RUNDIR
#define P_RUNDIR "/tmp"
#endif
#define THREAD_COUNT 4
extern int errno;
extern char *acltypes[];
/* To check for memory leaks */
extern int vlink_count;
extern int pattrib_count;
extern int acl_count;
extern int pfile_count;
extern int preq_count;
extern int ptext_count;
extern int string_count;
extern int vlink_max;
extern int pattrib_max;
extern int acl_max;
extern int pfile_max;
extern int preq_max;
extern int ptext_max;
extern int string_max;
extern int pQlen;
static cmd_lookup();
VLINK check_fwd();
char *month_sname();
char *check_nfs();
static char prog[40];
static int fault_count = 0;
static char last_request[MAX_PTXT_LEN] = "";
static char *last_error = NULL;
static char st_time_str[40];
static int in_port = -1;
static char *in_parg = "-p-1";
static int req_count = 0;
static int crdir_count = 0;
static int crlnk_count = 0;
static int crobj_count = 0;
static int dellnk_count = 0;
static int eoi_count = 0;
static int goi_count = 0;
static int list_count = 0;
static int lacl_count = 0;
static int modl_count = 0;
static int macl_count = 0;
static int status_count = 0;
static int upddir_count = 0;
int oldform_count = 0;
char shadow[MAXPATHLEN] = P_FSHADOW;
char pfsdat[MAXPATHLEN] = P_FSTORAGE;
char dirshadow[MAXPATHLEN] = DSHADOW;
char dircont[MAXPATHLEN] = DCONTENTS;
#ifdef ARCHIE
extern int prioritize_request();
#endif
#ifdef PSRV_ROOT
char root[MAXPATHLEN] = PSRV_ROOT;
#else
char root[MAXPATHLEN] = "";
#endif
#ifdef AFTPDIRECTORY
char aftpdir[MAXPATHLEN] = AFTPDIRECTORY;
#else
char aftpdir[MAXPATHLEN] = "";
#endif
#ifdef AFSDIRECTORY
char afsdir[MAXPATHLEN] = AFSDIRECTORY;
#else
char afsdir[MAXPATHLEN] = "";
#endif
#ifdef DATABASE_PREFIX
char *db_prefix = DATABASE_PREFIX;
#else
char *db_prefix = "";
#endif
char hostname[MAXPATHLEN] = ""; /* Server's host name */
char hostwport[MAXPATHLEN+30] = ""; /* Host name w/ port if non-standard */
int f;
main(argc, argv)
int argc;
char *argv[];
{
int mflag = 0; /* Manual start of server */
int on = 1;
struct sockaddr_in from;
int port_no;
struct hostent *current_host;
int fromlen;
PTEXT pkt;
PREQ curr_req;
register int n;
int child;
int retval;
long now;
struct tm *tm;
strcpy(prog,argv[0]);
umask(0);
/* If first arg is "-m" then continue to run */
/* from this terminal. */
if (argc > 1 && !strcmp(argv[1],"-m")) {
mflag++;
argc--;
argv++;
}
/* If first arg is "-p#" then privileged UDP port already open */
/* Note: Eventually, this will treat a number as an FD, a string */
/* following the -p as a name to look up in /etc/services and a */
/* number preceded by a # as a port number. In the latter two */
/* cases, bind port would be called. For now, however, bind */
/* port must be called in addition to any port that is passed */
if (argc > 1 && !strncmp(argv[1],"-p",2)) {
in_parg = argv[1];
sscanf(argv[1],"-p%d",&in_port);
set_prvport(in_port);
argc--;
argv++;
}
/* If first arg is "-F" then set fault count from next argument */
if (argc > 1 && !strncmp(argv[1],"-F",2)) {
fault_count = -1;
sscanf(argv[1],"-F%d",&fault_count);
argc--;
argv++;
}
/* If first arg is "-E" then set last_error */
if (argc > 1 && !strncmp(argv[1],"-E",2)) {
last_error = argv[1]+2;
argc--;
argv++;
}
/* usage */
if ((argc > 7) || (argc > 1 && !strcmp(argv[1],"-h"))) {
fprintf(stderr,
"Usage: dirsrv [-m] root shadow data aftp afs hostname\n");
exit(1);
}
if ((argc > 1) && *(argv[1]))
strcpy(root,argv[1]);
if ((argc > 2) && *(argv[2]))
strcpy(shadow,argv[2]);
if ((argc > 3) && *(argv[3]))
strcpy(pfsdat,argv[3]);
if ((argc > 4) && *(argv[4]))
strcpy(aftpdir,argv[4]);
if ((argc > 5) && *(argv[5]))
strcpy(afsdir,argv[5]);
if ((argc > 6) && *(argv[6]))
strcpy(hostname,argv[6]);
/* Here we should really get the host name in cannonical form */
if(*hostname == '\0') {
#ifndef PSRV_HOSTNAME
strncpy(hostname,myhostname(),sizeof(hostname));
#else
strncpy(hostname,PSRV_HOSTNAME,sizeof(hostname));
#endif PSRV_HOSTNAME
}
ucase(hostname);
/* Note our start time */
(void) time(&now);
tm = gmtime(&now);
sprintf(st_time_str,"%2d-%s-%02d %02d:%02d:%02d UTC",tm->tm_mday,
month_sname(tm->tm_mon + 1),tm->tm_year,
tm->tm_hour, tm->tm_min, tm->tm_sec);
retval = chdir(P_RUNDIR);
if(retval) plog(L_STATUS,NULL,NULL,"Startup - chdir failed: %d",errno,0);
/* Eventually, we will only set up and bind a port if one */
/* wasn't already passed to us using the -p option. Until */
/* all clients can support alternative ports, however, we */
/* must bind the DIRSRV port in addition to any that were */
/* passed to us. Note that at this point, unless we are */
/* running as root (which we should not be) we would not */
/* have been able to bind the priveleged port. */
port_no = bind_port("dirsrv");
#ifdef TAG_UNASSIGNED_PORT
if((in_port < 0) && (port_no != PROSPERO_PORT))
sprintf(hostwport,"%s(%d)",hostname,port_no);
else
#endif
strcpy(hostwport,hostname);
#ifdef ARCHIE
/* Set queueing policy */
set_queuing_policy(prioritize_request,0);
#endif /* ARCHIE */
if (!mflag) {
if ((child = fork()) != 0) {
printf("%s started, PID=%d, PORT=%d\n",
prog, child, port_no);
exit(0);
}
setup_disc();
}
else printf("%s started, PORT=%d\n", prog, port_no);
plog(L_STATUS,NULL,NULL,"Startup - Mode: %s, Root: %s, Shadow: %s, Aftpdir: %s, Host: %s",
(mflag ? "manual" : "server"),root,shadow,aftpdir,hostwport,0);
/* set dirsend timeout for chasing forwarding pointers */
set_dirsend_retry(4,1);
#ifndef THREADS
/* receive loop */
for (;;) {
curr_req = get_next_request();
pkt = curr_req->recv;
#ifdef DEBUG
strcpy(last_request,pkt->start); /* For error logging */
#endif DEBUG
req_count++;
dirsrv(curr_req, pkt);
}
#else /* THREADS */
/* receive loop */
for (;;) {
int free_count = THREAD_COUNT;
if(threadcount > 0) {
curr_req = get_next_request();
pkt = curr_req->recv;
#ifdef DEBUG
strcpy(last_request,pkt->start); /* For error logging */
#endif DEBUG
req_count++;
free_count--;
dirsrv(curr_req, pkt);
}
else {
free_count++;
}
}
#endif
}
dirsrv(req, pkt)
PREQ req;
PTEXT pkt;
{
static long client_host;
#ifdef DATABASE_PREFIX
static ACL database_acl;
static int dbacl_read = 0;
#endif DATABASE_PREFIX
/* The following are set in one line and used by subsequent */
/* lines of the same message */
int client_version = MAX_VERSION; /* Protocol version nbr */
char auth_type[40]; /* Type of Authentication */
char authent[160]; /* Authentication data */
char client_id[160]; /* Authenticated username */
char client_dir[MAXPATHLEN]; /* Current directory */
long dir_version = -1; /* Directory version nbr */
long dir_magic_no = -1; /* Directory magic number */
#ifdef ARCHIE
int max_list_commands = 5; /* Max lists in request */
#endif /* ARCHIE */
CINFO_ST id_st;
CINFO id = & id_st;
/* The following are used while processing the current line */
char *command; /* The current line */
char *command_next = NULL; /* The next line */
int cmd_code; /* Operation code */
VDIR_ST dir_st; /* Directory contents used ... */
VDIR dir = &dir_st; /* by individual lines */
PFILE fi; /* individual lines */
VLINK fl; /* List of forwarding pointers */
VLINK fp; /* The current fp */
char *components; /* Components to be processed */
char *remcomp; /* Remaining components */
char localexp; /* OK to exp ul for remcomp */
VLINK uexp; /* Current link being expanded */
char attribfl; /* Send back atribues in list */
int item_count = 0; /* Count of returned items */
/* Temporaries */
char dir_type[40]; /* Type or dir name (ASCII) */
char *amarg; /* Arguments for access method */
VLINK clink; /* For stepping through links */
VLINK crep; /* For stepping through replicas*/
VLINK cfil; /* For stepping through filters */
PATTRIB ca; /* Current Attribute */
char *suffix; /* Trailing component(s) */
int rsinfo_ret; /* Ret Val from dsrfinfo */
int verify_dir; /* Only verifying the directory */
int retval;
int tmp;
int lpriv; /* LPRIV option for CREATE-DIR */
ACL wacl; /* Working access control list */
int laclchkl; /* Cached ACL check */
int daclchkl; /* Cached ACL check */
int laclchkr; /* Cached ACL check */
int daclchkr; /* Cached ACL check */
int aclchk; /* Cached ACL check */
ACL nacl; /* New ACL entry */
/* Temporaries for use by sscanf */
char t_ltype;
char t_name[MAX_DIR_LINESIZE];
char t_type[MAX_DIR_LINESIZE];
char t_htype[MAX_DIR_LINESIZE];
char t_host[MAX_DIR_LINESIZE];
char t_ntype[MAX_DIR_LINESIZE];
char t_fname[MAX_DIR_LINESIZE];
char t_args[MAX_DIR_LINESIZE];
char t_options[MAX_DIR_LINESIZE];
char t_acetype[MAX_DIR_LINESIZE];
char t_atype[MAX_DIR_LINESIZE];
char t_rights[MAX_DIR_LINESIZE];
char t_principals[MAX_DIR_LINESIZE];
int t_num;
int n_options;
char insrights[MAX_DIR_LINESIZE];
char qatype[MAX_DIR_LINESIZE];
char qrights[MAX_DIR_LINESIZE];
vdir_init(dir);
#ifdef DATABASE_PREFIX
if(!dbacl_read++) {
retval = dsrdir(DATABASE_PREFIX,0,dir,NULL,0);
if(!retval) database_acl = dir->dacl;
else aclfree(dir->dacl);
dir->dacl = NULL;
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
}
#endif DATABASE_PREFIX
id->ainfo_type = 0;
id->authenticator = NULL;
id->userid = NULL;
bcopy(&(req->fromto.sin_addr),&(id->haddr),sizeof(id->haddr));
id->port = ntohs(req->fromto.sin_port);
id->previous = NULL;
id->next = NULL;
client_host = req->fromto.sin_addr.s_addr;
*client_dir = '\0';
strcpy(authent,"NONE");
strcpy(client_id,"");
command_next = pkt->start;
get_token(command,'\n'); /* Defined in pprot.h */
while(command) {
cmd_code = cmd_lookup(command);
switch(cmd_code) {
case STATUS:
status_count++;
replyf(req,"Prospero server (%s) %s",PFS_RELEASE,hostwport,0);
if(fault_count)
replyf(req,"Faults since startup %d",fault_count,0);
replyf(req,"Requests since startup %d (%d+%d+%d %d+%d+%d %d %d+%d+%d %d %d)%s",
req_count, list_count, goi_count, lacl_count,
crlnk_count, crdir_count, crobj_count, dellnk_count,
modl_count, eoi_count, macl_count, upddir_count,
status_count, (oldform_count ? " OF" : ""), 0);
replyf(req,"Started: %s",st_time_str,0);
#ifdef PROSPERO_CONTACT
replyf(req,"Contact: %s",PROSPERO_CONTACT,0);
#endif PROSPERO_CONTACT
replyf(req," Memory: %d(%d)vl %d(%d)at %d(%d)acl %d(%d)fi %d(%d)pr %d(%d)pt %d(%d)str",
vlink_count,vlink_max,pattrib_count,pattrib_max,
acl_count,acl_max,pfile_count,pfile_max,preq_count,
preq_max,ptext_count,ptext_max,
string_count,string_max,0);
#ifndef PSRV_READ_ONLY
if(*pfsdat) replyf(req," Data: %s", pfsdat, 0);
#endif PSRV_READ_ONLY
if(*root) replyf(req," Root: %s", root, 0);
if(*aftpdir) replyf(req," AFTP: %s", aftpdir, 0);
if(*afsdir) replyf(req," AFS: %s", afsdir, 0);
if(*db_prefix) replyf(req," DB: %s", db_prefix, 0);
if(last_error) replyf(req," Error: %s",last_error,0);
plog(L_DIR_PINFO, client_host, client_id, "STATUS Request",0);
break;
case VERSION:
tmp = sscanf(command,"VERSION %d",&client_version);
if(tmp != 1) {
replyf(req,"VERSION %d (%s)",MAX_VERSION,PFS_RELEASE,0);
break;
}
if(client_version == MAX_VERSION) break;
if((client_version < MAX_VERSION) &&
(client_version >= MIN_VERSION)) {
plog(L_DIR_PWARN,client_host,NULL,"Old version in use: %d",
client_version, 0);
break;
}
if(MAX_VERSION == MIN_VERSION)
sendmf(req,"VERSION-NOT-SUPPORTED TRY %d",MAX_VERSION, 0);
else sendmf(req,"VERSION-NOT-SUPPORTED TRY %d-%d",
MIN_VERSION,MAX_VERSION, 0);
plog(L_DIR_PERR,client_host,NULL,"Unimplemented version in use: %d",
client_version, 0);
return(PFAILURE);
break;
case AUTHENTICATOR:
tmp = sscanf(command,"AUTHENTICATOR %s %s",auth_type,authent);
if(tmp != 2) {
sendmf(req,"ERROR Invalid arguments: %s",command, 0);
plog(L_DIR_PERR, client_host, NULL,
"Invalid AUTHENTICATOR command: %s", command, 0);
return(PFAILURE);
}
if(strcmp(auth_type,"UNAUTHENTICATED")) {
sendmf(req,"ERROR authentication type %s not supported",
auth_type,0);
plog(L_DIR_ERR,client_host,NULL,"Invalid auth-type %s: %s",
auth_type,command,0);
return(PFAILURE);
}
strcpy(client_id,authent);
id->userid = client_id;
id->auth_type = auth_type;
id->authenticator = authent;
break;
case DIRECTORY:
dir_version = 0;
dir_magic_no = 0;
tmp = sscanf(command,"DIRECTORY %s %s %d %d",
dir_type,client_dir,&dir_version,&dir_magic_no);
if(tmp < 2) {
sendmf(req,"ERROR Invalid arguments: %s",command, 0);
plog(L_DIR_PERR,client_host,client_id,
"Invalid DIRECTORY command: %s",command,0);
return(PFAILURE);
}
if(strcmp(dir_type,"ASCII")) {
sendmf(req,"ERROR id-type %s not supported",dir_type,0);
plog(L_DIR_ERR,client_host,client_id,"Invalid id-type: %s",
command, 0);
return(PFAILURE);
}
if(check_path(client_dir) == FALSE) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Invalid directory name: %s",client_dir,0);
return(PFAILURE);
}
break;
more_comps:
/* Set the directory for the next component */
/* At this point, clink contains the link for the next */
/* directory, and the directory itself is still filled */
/* in. We should save away the directory information, */
/* then free what remains */
dir_version = clink->version;
dir_magic_no = clink->f_magic_no;
strcpy(dir_type,clink->nametype);
strcpy(client_dir,clink->filename);
if(strcmp(dir_type,"ASCII")) {
sendmf(req,"ERROR id-type %s not supported",dir_type,0);
plog(L_DIR_ERR,client_host,client_id,"Invalid id-type: %s",
command, 0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(check_path(client_dir) == FALSE) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Invalid directory name: %s",client_dir,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
components = remcomp;
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
goto continue_list;
case LIST:
list_count++;
#ifdef ARCHIE
if(max_list_commands-- <= 0) {
sendmf(req,"FAILURE NOT-AUTHORIZED Too many list commands in a single request",0);
plog(L_AUTH_ERR,client_host,client_id,
"Too many list commands",0);
return(PFAILURE);
}
#endif /* ARCHIE */
tmp = sscanf(command,"LIST %s COMPONENTS %[^\n]",
t_options, t_name);
if(tmp < 2) components = "*";
else components = t_name;
/* If no options, parse again */
if(strcmp(t_options,"COMPONENTS")==0) {
tmp = sscanf(command,"LIST COMPONENTS %[^\n]", t_name);
if(tmp < 1) components = "*";
else components = t_name;
}
if(sindex(t_options,"VERIFY")) verify_dir = 1;
else verify_dir = 0;
#ifndef DONTSUPPORTOLD
if(strcmp(components,"%#$PRobably_nOn_existaNT$#%")==0) {
components = "*";
verify_dir = 1;
}
#endif
/* If EXPAND specified, remeber that fact */
if(sindex(t_options,"EXPAND") || sindex(t_options,"LEXPAND"))
localexp = 2;
else localexp = 0;
if(sindex(t_options,"ATTRIBUTES")) attribfl = DSRD_ATTRIBUTES;
else attribfl = 0;
plog(L_DIR_REQUEST, client_host, client_id, "L%s %s %s",
(verify_dir ? "V" : " "), client_dir, components, 0);
/* Here's where we start to resolve additional components */
continue_list:
remcomp = index(components,'/');
if(remcomp) {
*(remcomp++) = '\0';
if(!*remcomp) remcomp = NULL;
}
uexp = NULL;
/* If only expanding last component, clear the flag */
if(localexp == 1) localexp = 0;
/* If remaining components, expand for this component only */
if(remcomp && !localexp) localexp = 1;
#ifdef NODOTDOT
if(strcmp(components,"..") == 0) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Invalid component name: %s %s",client_dir,components,0);
return(PFAILURE);
}
#endif NODOTDOT
exp_ulink:
*p_err_string = '\0';
#ifdef DATABASE_PREFIX
if(strncmp(client_dir,DATABASE_PREFIX,
strlen(DATABASE_PREFIX)) == 0) {
if(database_acl && !check_acl(database_acl,NULL,id,"r")) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized database request: %s %s",client_dir,t_name,0);
return(PFAILURE);
}
/* This could take a while, tell client not to retry */
transmit_wait(req,180);
retval = dsdb(client_dir,&components,&remcomp,
dir,verify_dir);
}
else
#endif DATABASE_PREFIX
retval = dsrdir(client_dir,dir_magic_no,dir,uexp,attribfl);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
return(PFAILURE);
}
/* If some other failure, say so */
if(retval == DIRSRV_NOT_AUTHORIZED) {
if(*p_err_string)
sendmf(req,"FAILURE NOT-AUTHORIZED %s",p_err_string,0);
else sendmf(req,"FAILURE NOT-AUTHORIZED",0);
return(PFAILURE);
}
/* If some other failure, say so */
if(retval) {
sendmf(req,"FAILURE SERVER-FAILED",0);
return(PFAILURE);
}
/* Cache the default answers for ACL checks */
daclchkl = check_acl(dir->dacl,NULL,id,"l");
daclchkr = check_acl(dir->dacl,NULL,id,"r");
/* Here we must send back the links, excluding those that do */
/* not match the component name. For each link, we must also */
/* send back any replicas or links with conflicting names */
clink = dir->links;
while(clink) {
crep = clink;
while(crep) {
/* If ->expanded set means we already returned it */
if(crep->expanded) {
crep = crep->next;
continue;
}
/* Check individual ACL only if necessary */
laclchkl = daclchkl; laclchkr = daclchkr;
if(crep->acl) {
laclchkl = check_acl(dir->dacl,crep->acl,id,"l");
laclchkr = check_acl(dir->dacl,crep->acl,id,"r");
}
if(!verify_dir && wcmatch(crep->name,components) &&
(laclchkl || (laclchkr &&
(strcmp(crep->name,components)==0)))) {
if(laclchkr) {
if(remcomp && !strcmp(crep->host,hostwport) &&
!(crep->filters) && !item_count) {
/* If components remain on this host */
/* don't reply, but continue searching */
goto more_comps;
}
replyf(req,"LINK L %s %s %s %s %s %s %d %d",
crep->type, quote(crep->name),
crep->hosttype, crep->host,
crep->nametype, crep->filename,
crep->version,crep->f_magic_no,0);
}
else {
replyf(req,"LINK L NULL %s NULL NULL NULL NULL 0 0",
quote(crep->name),0);
}
/* Using ->expanded to indicate returned */
crep->expanded = TRUE;
item_count++;
/* If link attributes are to be returned, do so */
/* For now, only link attributes returned */
ca = crep->lattrib;
while(ca && attribfl) {
/* For now return all attributes. To be done: */
/* return only those requested */
if(1) {
replyf(req,"LINK-INFO %s %s %s %s",
((ca->precedence==ATR_PREC_LINK) ? "LINK":
((ca->precedence==ATR_PREC_REPLACE)? "REPLACEMENT":
((ca->precedence==ATR_PREC_ADD) ? "ADDITIONAL":
"CACHED"))),
ca->aname,ca->avtype,ca->value.ascii,0);
}
ca = ca->next;
}
/* If there are any filters, send them back too */
cfil = crep->filters;
while(cfil && laclchkr) {
if(cfil->args) replyf(req,"FILTER %c %s %s %s %s %d %d ARGS '%s'",
cfil->linktype,
cfil->hosttype, cfil->host,
cfil->nametype, cfil->filename,
cfil->version,cfil->f_magic_no,
/* Handle qwuoting properly*/
/*quote(*/cfil->args/*)*/,0);
else replyf(req,"FILTER %c %s %s %s %s %d %d",
cfil->linktype,
cfil->hosttype, cfil->host,
cfil->nametype, cfil->filename,
cfil->version,cfil->f_magic_no,0);
cfil = cfil->next;
}
}
/* Replicas are linked through next, not replicas */
/* But the primary link is linked to the replica */
/* list through replicas */
if(crep == clink) crep = crep->replicas;
else crep = crep->next;
}
clink = clink->next;
}
/* here we must send back the unexpanded union links */
clink = dir->ulinks;
while(clink && !verify_dir) {
if(!clink->expanded &&
check_acl(dir->dacl,clink->acl,id,"r")) {
if(localexp && !(clink->filters) &&
!strcmp(clink->host,hostwport)) {
/* Set the directory for the next component */
/* At this point, clink contains the link */
/* for the next directory */
dir_version = clink->version;
dir_magic_no = clink->f_magic_no;
strcpy(dir_type,clink->nametype);
strcpy(client_dir,clink->filename);
if(strcmp(dir_type,"ASCII")) {
sendmf(req,"ERROR id-type %s not supported",
dir_type,0);
plog(L_DIR_ERR,client_host,client_id,
"Invalid id-type: %s", command, 0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(check_path(client_dir) == FALSE) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Invalid directory name: %s",client_dir,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
clink->expanded = TRUE;
uexp = clink;
goto exp_ulink;
}
/* Don't do any more expanding */
localexp = 0;
replyf(req,"LINK %c %s %s %s %s %s %s %d %d",
clink->linktype,
clink->type, quote(clink->name),
clink->hosttype, clink->host,
clink->nametype,clink->filename,
clink->version,clink->f_magic_no,0);
item_count++;
/* if there are any filters */
cfil = clink->filters;
while(cfil) {
if(cfil->args) replyf(req,"FILTER %c %s %s %s %s %d %d ARGS '%s'",
cfil->linktype,
cfil->hosttype, cfil->host,
cfil->nametype, cfil->filename,
cfil->version,cfil->f_magic_no,
/* Handle quoting properly*/
/*quote(*/cfil->args/*)*/,0);
else replyf(req,"FILTER %c %s %s %s %s %d %d",
cfil->linktype,
cfil->hosttype, cfil->host,
cfil->nametype, cfil->filename,
cfil->version,cfil->f_magic_no,0);
cfil = cfil->next;
}
}
clink = clink->next;
}
/* If none, match, say so */
if(!item_count)
replyf(req,"NONE-FOUND",0);
/* Otherwise, if components remain say so */
else if(remcomp && *remcomp)
replyf(req,"UNRESOLVED %s",remcomp,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
break;
case LIST_ACL:
lacl_count++;
*t_name = '\0';
/* First arg is options. All others are optional. */
/* If a second argument is specified, it is the */
/* link for which the ACL is to be returned */
/* if the OBJECT option is specified, then args */
/* 2-5 identify the object instead of the link */
tmp = sscanf(command,"LIST-ACL %s %s %*s %*d %*d",
t_options, t_name);
/* Log and return a better message */
if((tmp < 1) ||
((tmp < 2) && (strcmp(t_options,"DIRECTORY") != 0))) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
command, 0);
return(PFAILURE);
}
/* Do we need a better log message */
plog(L_DIR_REQUEST,client_host,client_id,"LA %s %s",
client_dir,t_name,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
wacl = NULL;
/* Only LINK and DIRECTORY are presently implemented */
if(sindex(t_options,"LINK")) {
/* Need to find the link so we can check its ACL */
clink = dir->links;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
if(!clink) {
clink = dir->ulinks;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
}
if(!clink) {
sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
client_dir, t_name,0);
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
wacl = clink->acl;
aclchk = check_acl(dir->dacl,clink->acl,id,"v");
}
else if(sindex(t_options,"DIRECTORY")) {
wacl = dir->dacl;
aclchk = check_acl(dir->dacl,NULL,id,"V");
}
else {
sendmf(req,"ERROR invalid option",0);
plog(L_DIR_PERR,client_host,client_id,"Invalid option: %s",
command, 0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
/* If not authorized, say so */
if(!aclchk) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized LIST-ACL: %s %s",client_dir,t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(wacl == NULL) {
if(sindex(t_options,"LINK")) /* Link default is diracl */
replyf(req,"ACL DIRECTORY '' '' ''",0);
else {
replyf(req,"ACL DEFAULT '' '' ''",0);
replyf(req,"ACL SYSTEM '' '' ''",0);
}
}
else while (wacl) {
strcpy(qatype,quote(wacl->atype));
strcpy(qrights,quote(wacl->rights));
replyf(req,"ACL %s %s %s %s",
acltypes[wacl->acetype],qatype,
qrights,quote(wacl->principals),0);
wacl = wacl->next;
}
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
#ifdef DATABASE_PREFIX
if(strcmp(client_dir,DATABASE_PREFIX) == 0) {
aclfree(database_acl);
database_acl = dir->dacl;
} else
#endif
aclfree(dir->dacl);
dir->dacl = NULL;
break;
#ifndef PSRV_READ_ONLY
case UPDATE:
upddir_count++;
components = sindex(command,"COMPONENTS");
if(!components || (strlen(components) < 12)) components = "*";
else components += 11;
plog(L_DIR_UPDATE, client_host, client_id, "U %s %s",
client_dir, components,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
/* Here we must check for forwarding of each link and */
/* update it to reflect the new target */
clink = dir->links;
while(clink) {
if(wcmatch(clink->name,components)) {
/* Check for forwarding */
if(retrieve_fp(clink) == PSUCCESS) item_count++;
/* If filters, check them too */
cfil = clink->filters;
while(cfil) {
if(retrieve_fp(cfil) == PSUCCESS) item_count++;
cfil = cfil->next;
}
}
clink = clink->next;
}
/* here we must process the union, */
/* replica and propagate links */
clink = dir->ulinks;
while(clink) {
if(wcmatch(clink->name,components)) {
/* Check for forwarding */
if(retrieve_fp(clink) == PSUCCESS) item_count++;
/* If filters, check them too ***/
cfil = clink->filters;
while(cfil) {
if(retrieve_fp(cfil) == PSUCCESS) item_count++;
cfil = cfil->next;
}
}
clink = clink->next;
}
retval = 0;
if(item_count) retval = dswdir(client_dir,dir);
/* Indicate how many updated */
if(retval) replyf(req,"FAILED to UPDATE %d links",item_count,0);
else replyf(req,"UPDATED %d links",item_count,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
break;
case CREATE_LINK:
crlnk_count++;
clink = vlalloc();
tmp = sscanf(command,"CREATE-LINK %c %s %s %s %s %s %s %d %d",
&t_ltype,t_name,t_type,t_htype,t_host,
t_ntype,t_fname,
&(clink->version),&(clink->f_magic_no));
/* Log and return a better message */
if(tmp < 7) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR, client_host, client_id,
"Too few arguments: %s", command, 0);
return(PFAILURE);
}
if (t_ltype == 'U') clink->linktype = 'U';
clink->name = stcopyr(unquote(t_name),clink->name);
clink->type = stcopyr(t_type,clink->type);
clink->hosttype = stcopyr(t_htype,clink->hosttype);
clink->host = stcopyr(t_host,clink->host);
clink->nametype = stcopyr(t_ntype,clink->nametype);
clink->filename = stcopyr(t_fname,clink->filename);
/* Do we need a better log message */
plog(L_DIR_UPDATE, client_host, client_id,
"CL %s %c %s %s %s %s %s %s", client_dir,
clink->linktype, clink->name, clink->type, clink->hosttype,
clink->host, clink->nametype,clink->filename,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
/* If not authorized, say so */
if(!check_acl(dir->dacl,NULL,id,"I")) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized CREATE-LINK: %s %s",client_dir,
components,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
/* Make sure creator has all rights to link */
if(!check_acl(dir->dacl,NULL,id,"alrmd")) {
/* If not, grant full access */
nacl = acalloc();
nacl->acetype = ACL_ASRTHOST;
nacl->rights = stcopyr("alrmd",nacl->rights);
nacl->principals = stcopyr(id->userid,nacl->principals);
change_acl(&(clink->acl),nacl,id,MACL_ADD|MACL_LINK,dir->dacl);
}
retval = vl_insert(clink,dir,VLI_NOCONFLICT);
if((retval == VL_INSERT_ALREADY_THERE) ||
(retval == UL_INSERT_ALREADY_THERE)) {
sendmf(req,"FAILURE ALREADY-EXISTS %s",clink->name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
else if(retval == VL_INSERT_CONFLICT) {
sendmf(req,"FAILURE NAME-CONFLICT %s",clink->name,0);
plog(L_DIR_ERR, client_host, client_id,
"Conflicting link already exists: %s %s", client_dir, clink->name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(!retval) retval = dswdir(client_dir,dir);
/* if successfull say so (need to clean this up) */
if(!retval)
replyf(req,"SUCCESS",0);
else replyf(req,"FAILURE",0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
break;
case MODIFY_ACL:
macl_count++;
*t_name = '\0';
tmp = sscanf(command,"MODIFY-ACL %s %s %s %s %s %[^\n]",
t_options, t_name, t_acetype, t_atype,
t_rights, t_principals);
/* Log and return a better message */
if(tmp < 6) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
command, 0);
return(PFAILURE);
}
/* Do we need a better log message */
plog(L_DIR_UPDATE,client_host,client_id,"MA %s %s %s %s %s %s %s",
client_dir,t_name,t_options,t_acetype,t_atype,t_rights,
t_principals,0);
strcpy(t_name,unquote(t_name));
nacl = acalloc();
for(nacl->acetype = 0;acltypes[nacl->acetype];(nacl->acetype)++) {
if(strcmp(acltypes[nacl->acetype],t_acetype)==0)
break;
}
if(acltypes[nacl->acetype] == NULL) nacl->acetype = 0;
nacl->atype = stcopyr(unquoten(t_atype),nacl->atype);
nacl->rights = stcopyr(unquoten(t_rights),nacl->rights);
nacl->principals = stcopyr(unquoten(t_principals),nacl->principals);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
n_options = 0;
/* Parse the options */
if(sindex(t_options,"NOSYSTEM")!=NULL) n_options|=MACL_NOSYSTEM;
if(sindex(t_options,"NOSELF")!=NULL) n_options|=MACL_NOSELF;
if(sindex(t_options,"DEFAULT")!=NULL) n_options|=MACL_DEFAULT;
if(sindex(t_options,"SET") != NULL) n_options |= MACL_SET;
if(sindex(t_options,"INSERT")!=NULL) n_options|=MACL_INSERT;
if(sindex(t_options,"DELETE")!=NULL) n_options|=MACL_DELETE;
if(sindex(t_options,"ADD")!=NULL) n_options|=MACL_ADD;
if(sindex(t_options,"SUBTRACT")!=NULL) n_options|=MACL_SUBTRACT;
if(sindex(t_options,"LINK")!=NULL) n_options|=MACL_LINK;
if(sindex(t_options,"DIRECTORY")!=NULL) n_options|=MACL_DIRECTORY;
if(sindex(t_options,"OBJECT")!=NULL) n_options|=MACL_OBJECT;
if(sindex(t_options,"INCLUDE")!=NULL) n_options|=MACL_INCLUDE;
wacl = dir->dacl;
if(!((n_options&MACL_OTYPE)^MACL_LINK)) {
/* Need to find the link so we can change its ACL */
clink = dir->links;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
if(!clink) {
clink = dir->ulinks;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
}
if(!clink) {
sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
client_dir, t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(clink->acl) wacl = clink->acl;
/* Check and update link ACL */
aclchk = check_acl(dir->dacl,clink->acl,id,"a");
if(!aclchk && nacl->rights && *(nacl->rights) &&
(!((n_options&MACL_OP)^MACL_ADD) ||
!((n_options&MACL_OP)^MACL_INSERT) ||
!((n_options&MACL_OP)^MACL_SUBTRACT) ||
!((n_options&MACL_OP)^MACL_DELETE))) {
if(!((n_options&MACL_OP)^MACL_ADD) ||
!((n_options&MACL_OP)^MACL_INSERT))
*insrights = ']';
else *insrights = '[';
strcpy(insrights+1,nacl->rights);
aclchk = check_acl(dir->dacl,clink->acl,id,insrights);
/* Don't use this to upgrade [ to a */
if(aclchk) n_options |= MACL_NOSELF;
}
/* If not authorized, say so */
if(!aclchk) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized LIST-ACL: %s %s",client_dir,t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
retval = change_acl(&(clink->acl),nacl,id,n_options,dir->dacl);
}
else if(!((n_options&MACL_OTYPE)^MACL_DIRECTORY)) {
/* Check and update directory ACL */
aclchk = check_acl(dir->dacl,NULL,id,"A");
if(!aclchk && nacl->rights && *(nacl->rights) &&
(!((n_options&MACL_OP)^MACL_ADD) ||
!((n_options&MACL_OP)^MACL_INSERT) ||
!((n_options&MACL_OP)^MACL_SUBTRACT) ||
!((n_options&MACL_OP)^MACL_DELETE))) {
if(!((n_options&MACL_OP)^MACL_ADD) ||
!((n_options&MACL_OP)^MACL_INSERT))
*insrights = '>';
else *insrights = '<';
strcpy(insrights+1,nacl->rights);
aclchk = check_acl(dir->dacl,NULL,id,insrights);
/* Don't use this to upgrade < to a */
if(aclchk) n_options |= MACL_NOSELF;
}
/* If not authorized, say so */
if(!aclchk) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized LIST-ACL: %s %s",client_dir,t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
retval = change_acl(&(dir->dacl),nacl,id,n_options,dir->dacl);
}
else {
sendmf(req,"ERROR invalid option",0);
plog(L_DIR_PERR,client_host,client_id,"Invalid option: %s",
command, 0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
/* if unsuccessfull say so (need to clean this up) */
if(retval) replyf(req,"FAILURE NOT-FOUND ACL",0);
else { /* Otherwise write the directory and indicate success */
retval = dswdir(client_dir,dir);
if(retval) replyf(req,"FAILURE",0);
else replyf(req,"SUCCESS",0);
}
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
break;
case MODIFY_LINK:
modl_count++;
cfil = vlalloc();
tmp = sscanf(command,"MODIFY-LINK %s FILTER ADD %c %s %s %s %s %d %d ARGS '%[^']",
t_name,&t_ltype,t_htype,t_host,t_ntype,t_fname,
&(cfil->version),&(cfil->f_magic_no),t_args);
/* Log and return a better message */
if(tmp < 6) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR, client_host, client_id,
"Too few arguments: %s", command, 0);
return(PFAILURE);
}
cfil->linktype = t_ltype;
cfil->hosttype = stcopyr(t_htype,cfil->hosttype);
cfil->host = stcopyr(t_host,cfil->host);
cfil->nametype = stcopyr(t_ntype,cfil->nametype);
cfil->filename = stcopyr(t_fname,cfil->filename);
if(tmp == 9) cfil->args = stcopyr(t_args,cfil->args);
/* Do we need a better log message */
plog(L_DIR_UPDATE, client_host, client_id,
"ML %s %s FA %c %s %s %s %s ARGS '%s'", client_dir,
t_name, cfil->linktype, cfil->hosttype, cfil->host,
cfil->nametype,cfil->filename, cfil->args,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
clink = dir->links;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
if(!clink) {
clink = dir->ulinks;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
}
if(!clink) {
sendmf(req,"FAILURE NOT-FOUND LINK %s",t_name,0);
plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
client_dir, t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
/* If not authorized, say so */
if(!check_acl(dir->dacl,clink->acl,id,"m")) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized MODIFY-LINK: %s %s",client_dir,
clink->name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
fl_insert(cfil,clink);
if(!retval) retval = dswdir(client_dir,dir);
/* if successfull say so (need to clean this up) */
if(!retval)
replyf(req,"SUCCESS",0);
else replyf(req,"FAILURE",0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
break;
case CREATE_DIRECTORY:
crdir_count++;
clink = vlalloc();
/* still have to read the remainder of the attributes */
tmp = sscanf(command,"CREATE-DIRECTORY %s %s",
t_options,t_name);
/* Log and return a better message */
if(tmp < 2) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
command, 0);
return(PFAILURE);
}
/* For now, VIRTRUAL option must be specified */
if(sindex(t_options,"VIRTUAL") == NULL) {
sendmf(req,"ERROR only VIRTUAL directories implemented",0);
plog(L_DIR_PERR,client_host,client_id,"Tried to create non-VIRTUAL directory: %s",
command, 0);
return(PFAILURE);
}
if(sindex(t_options,"LPRIV")) lpriv = 1;
else lpriv = 0;
clink->name = stcopyr(t_name,clink->name);
clink->type = stcopyr("DIRECTORY",clink->type);
clink->host = stcopyr(hostwport,clink->host);
strcpy(t_fname,client_dir);
strcat(t_fname,"/");
strcat(t_fname,t_name);
clink->filename = stcopyr(t_fname,clink->filename);
/* Do we need a better log message */
plog(L_DIR_UPDATE,client_host,client_id,"MKD %s %s",
client_dir, clink->name,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
/* If not authorized, say so */
if(!check_acl(dir->dacl,NULL,id,"I")) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized CREATE-DIRECTORY: %s %s",client_dir,
components,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
retval = vl_insert(clink,dir,VLI_NOCONFLICT);
if(retval == VL_INSERT_ALREADY_THERE) {
sendmf(req,"FAILURE ALREADY-EXISTS %s",clink->name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
else if(retval == VL_INSERT_CONFLICT) {
sendmf(req,"FAILURE NAME-CONFLICT %s",clink->name,0);
plog(L_DIR_ERR,client_host,client_id,
"Conflicting link already exists: %s %s",client_dir,clink->name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
if(!retval) retval = dswdir(client_dir,dir);
/* We should check if the new directory already */
/* exists and if so pick a new name for the */
/* physical instantiation **** */
/* Free the directory links, but leave ACL */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
dir->inc_native = FALSE;
/* Add creator to the ACL */
if(!lpriv || (!check_acl(dir->dacl,NULL,id,"AIlr"))) {
nacl = acalloc();
nacl->acetype = ACL_ASRTHOST;
if(lpriv) nacl->rights = stcopyr("AIlr",nacl->rights);
else nacl->rights = stcopyr("ALRMDI",nacl->rights);
nacl->principals = stcopyr(id->userid,nacl->principals);
change_acl(&(dir->dacl),nacl,id,MACL_ADD|MACL_DIRECTORY,dir->dacl);
}
if(!retval) retval = dswdir(t_fname,dir);
/* Free the ACL */
aclfree(dir->dacl); dir->dacl = NULL;
/* if successfull say so (need to clean this up) */
if(!retval)
replyf(req,"SUCCESS",0);
else replyf(req,"FAILURE",0);
break;
case DELETE_LINK:
dellnk_count++;
t_num = 1;
tmp = sscanf(command,"DELETE-LINK VLINK %s NUMBER %d",
t_name,&t_num);
/* Log and return a better message */
if(tmp < 1) {
sendmf(req,"ERROR too few arguments",0);
plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
command, 0);
return(PFAILURE);
}
/* Do we need a better log message */
plog(L_DIR_UPDATE,client_host,client_id,"RM %s %s # %d",
client_dir,t_name,t_num,0);
retval = dsrdir(client_dir,dir_magic_no,dir,NULL,0);
if(retval == DSRFINFO_FORWARDED) goto dforwarded;
/* If not a directory, say so */
if(retval == DSRDIR_NOT_A_DIRECTORY) {
sendmf(req,"NOT-A-DIRECTORY",0);
plog(L_DIR_ERR, client_host, client_id,
"Invalid directory name: %s", client_dir,0);
return(PFAILURE);
}
/* Need to find the link so we can check its ACL */
clink = dir->links;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
if(!clink) {
clink = dir->ulinks;
while(clink) {
if(strcmp(clink->name,t_name) == 0)
break;
clink = clink->next;
}
}
if(clink) wacl = clink->acl;
else wacl = NULL;
/* If not authorized, say so */
if(!check_acl(dir->dacl,wacl,id,"d")) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Unauthorized DELETE-LINK: %s %s",client_dir,
t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
clink = vl_delete(dir->links,t_name,t_num);
if(!perrno) dir->links = clink;
else {
clink = vl_delete(dir->ulinks,t_name,t_num);
if(!perrno) dir->ulinks = clink;
}
if(perrno) {
sendmf(req,"FAILURE NOT-FOUND FILE %s",t_name,0);
plog(L_DIR_ERR,client_host,client_id,"Link not found: %s %s",
client_dir, t_name,0);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
return(PFAILURE);
}
retval = dswdir(client_dir,dir);
/* Free the directory links */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
/* if successfull say so (need to clean this up) */
if(!retval)
replyf(req,"SUCCESS",0);
else replyf(req,"FAILURE",0);
break;
#endif
case GET_OBJECT_INFO:
goi_count++;
t_num = 0;
item_count = 0;
/* still have to read the remainder of the attributes */
tmp = sscanf(command,"GET-OBJECT-INFO %s ID %s %s %*d %d",
t_name,t_ntype,t_fname,&t_num);
/* Log and return a better message */
if(tmp < 3) {
sendmf(req,"ERROR wrong number of arguments",0);
plog(L_DIR_PERR,client_host,client_id,"Too few arguments: %s",
command, 0);
return(PFAILURE);
}
/* Do we need a better log message */
plog(L_DIR_REQUEST, client_host, client_id, "GOI %s %s",
t_name,t_fname,0);
if(check_path(t_fname) == FALSE) {
sendmf(req,"FAILURE NOT-AUTHORIZED",0);
plog(L_AUTH_ERR,client_host,client_id,
"Invalid directory name: %s",t_fname,0);
return(PFAILURE);
}
clink = vlalloc();
fi = pfalloc();
clink->nametype = stcopyr(t_ntype,clink->nametype);
clink->filename = stcopyr(t_fname,clink->filename);
clink->f_magic_no = t_num;
rsinfo_ret = dsrfinfo(clink->filename,clink->f_magic_no,fi);
if(strcmp(t_name,"FORWARDING-POINTER") == 0) {
if(rsinfo_ret == DSRFINFO_FORWARDED) {
if(fl = check_fwd(fi->forward,clink->filename,
clink->f_magic_no)) {
replyf(req,"OBJECT-INFO FORWARDING-POINTER LINK L FP %s %s %s %s %s %d %d",
quote(clink->name),
fl->hosttype, fl->host,
fl->nametype, fl->filename,
fl->version,fl->f_magic_no,0);
item_count++;
}
}
else if((clink->f_magic_no == 0) && (fi->f_magic_no != 0)) {
replyf(req,"OBJECT-INFO FORWARDING-POINTER LINK L FP %s %s %s %s %s %d %d",
quote(clink->name),
clink->hosttype, hostwport,
clink->nametype, clink->filename,
clink->version,fi->f_magic_no,0);
item_count++;
}
}
else if(rsinfo_ret == DSRFINFO_FORWARDED) {
fl = fi->forward; fi->forward = NULL;
fp = check_fwd(fl,clink->filename,clink->f_magic_no);
/* Free what we don't need */
pffree(fi); fi = NULL;
/* Got to location to return forwarded error */
goto forwarded;
}
else if(strcmp(t_name,"ACCESS-METHODS") == 0) {
oldform_count += 100000; /* Really old count is shifted */
plog(L_DIR_PWARN,client_host,client_id,
"Old format GOI AM",0);
#ifdef NFS_EXPORT
amarg = check_nfs(t_fname,client_host);
if(amarg) {
replyf(req,"OBJECT-INFO ACCESS-METHOD NFS %s",
amarg, 0);
item_count++;
}
#endif NFS_EXPORT
#ifdef AFSDIRECTORY
if(*afsdir && (sindex(clink->filename,afsdir) ==
clink->filename)) {
suffix = clink->filename + strlen(afsdir);
replyf(req,"OBJECT-INFO ACCESS-METHOD AFS %s",
suffix,0);
item_count++;
}
#endif AFSDIRECTORY
#ifdef AFTPDIRECTORY
if(*aftpdir && (sindex(clink->filename,aftpdir) ==
clink->filename)) {
suffix = clink->filename + strlen(aftpdir);
replyf(req,"OBJECT-INFO ACCESS-METHOD ANONYMOUS-FTP %s %s",
suffix,"BINARY",0);
item_count++;
}
#endif AFTPDIRECTORY
}
else if(strcmp(t_name,"ACCESS-METHOD") == 0) {
#ifdef NFS_EXPORT
amarg = check_nfs(t_fname,client_host);
if(amarg) {
replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII NFS %s",
amarg,0);
item_count++;
}
#endif NFS_EXPORT
#ifdef AFSDIRECTORY
if(*afsdir && (sindex(clink->filename,afsdir) ==
clink->filename)) {
suffix = clink->filename + strlen(afsdir);
replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII AFS %s",
suffix,0);
item_count++;
}
#endif AFSDIRECTORY
#ifdef AFTPDIRECTORY
/* Find the real name of the file and use it */
/* To check for AFTP access */
/* rnl = readlink(clink->filename,rname,MAXPATHLEN); */
/* if(rnl >= 0) *(rname+rnl) = '\0'; */
if(*aftpdir && (sindex(clink->filename,aftpdir) ==
clink->filename)) {
suffix = clink->filename + strlen(aftpdir);
replyf(req,"OBJECT-INFO ACCESS-METHOD ASCII ANONYMOUS-FTP %s %s",
suffix,"BINARY",0);
item_count++;
}
#endif AFTPDIRECTORY
}
else {
/* Here we must check the file info, look for matching */
/* attributes and return them */
if(rsinfo_ret <= 0) {
ca = fi->attributes;
while(ca) {
if((strcmp(t_name,ca->aname) == 0) ||
(strcmp(t_name,"ALL") == 0)) {
replyf(req,"OBJECT-INFO %s %s %s",
ca->aname,ca->avtype,ca->value.ascii,0);
item_count++;
}
ca = ca->next;
}
}
}
/* If none, match, say so */
if(!item_count)
replyf(req,"NONE-FOUND",0);
pffree(fi); fi = NULL;
vlfree(clink);
break;
case RESTART:
plog(L_STATUS,client_host,client_id,
"Server restarted (restart message received)",0);
sendmf(req,"RESTARTING",0);
restart_server(0,NULL);
break;
#ifdef DIE
case TERMINATE:
plog(L_STATUS,client_host,client_id,
"Server killed (terminate message received)",0);
sendmf(req,"TERMINATING",0);
log_stats();
exit(0);
#endif DIE
default:
plog(L_DIR_PERR,client_host,client_id,
"Unknown message: %s",command);
replyf(req,"UNIMPLEMENTED %s",command,0);
}
get_token(command,'\n'); /* Defined in pprot.h */
continue;
dforwarded:
fl = dir->f_info->forward; dir->f_info->forward = NULL;
fp = check_fwd(fl,client_dir,dir_magic_no);
/* Free what we don't need */
vllfree(dir->links); dir->links = NULL;
vllfree(dir->ulinks); dir->ulinks = NULL;
aclfree(dir->dacl); dir->dacl = NULL;
pffree(dir->f_info);
forwarded:
if(fp) {
replyf(req,"FORWARDED %s %s %s %s %d %d",
fp->hosttype,fp->host,fp->nametype,fp->filename,
fp->version,fp->f_magic_no,0);
}
else replyf(req,"FORWARDED",0);
vllfree(fl);
get_token(command,'\n'); /* Defined in pprot.h */
}
sendm(req,NULL);
return(PSUCCESS);
}
/*
* cmd_lookup - lookup the command name and return integer
*
* CMD_LOOKUP takes a pointer to a string containing a command.
* It then looks up the first word found in the string and
* returns an int that can be used in a switch to dispatch
* to the correct routines.
*
* This has been optimzed for the swerver side of the VFS protocol.
*/
static cmd_lookup(cmd)
char *cmd;
{
switch(*cmd) {
case 'A':
if(!strncmp(cmd,"AUTHENTICATOR",13))
return(AUTHENTICATOR);
else return(UNIMPLEMENTED);
#ifndef PSRV_READ_ONLY
case 'C':
if(!strncmp(cmd,"CREATE-OBJECT",11))
return(CREATE_OBJECT);
else if(!strncmp(cmd,"CREATE-LINK",11))
return(CREATE_LINK);
else if(!strncmp(cmd,"CREATE-DIRECTORY",16))
return(CREATE_DIRECTORY);
else return(UNIMPLEMENTED);
#endif
case 'D':
if(!strncmp(cmd,"DELETE-LINK",11))
#ifndef PSRV_READ_ONLY
return(DELETE_LINK);
#else
return(UNIMPLEMENTED);
#endif
else if(!strncmp(cmd,"DIRECTORY",9))
return(DIRECTORY);
else return(UNIMPLEMENTED);
#ifndef PSRV_READ_ONLY
case 'E':
if(!strncmp(cmd,"EDIT-OBJECT-INFO",14))
return(EDIT_OBJECT_INFO);
else return(UNIMPLEMENTED);
#endif
case 'G':
if(!strncmp(cmd,"GET-OBJECT-INFO",13))
return(GET_OBJECT_INFO);
else return(UNIMPLEMENTED);
case 'L':
if(!strncmp(cmd,"LIST-ACL",8))
return(LIST_ACL);
else if(!strncmp(cmd,"LIST",4))
return(LIST);
else return(UNIMPLEMENTED);
#ifndef PSRV_READ_ONLY
case 'M':
if(!strncmp(cmd,"MODIFY-ACL",10))
return(MODIFY_ACL);
else if(!strncmp(cmd,"MODIFY-LINK",11))
return(MODIFY_LINK);
else return(UNIMPLEMENTED);
#endif
case 'P':
if(!strncmp(cmd,"PACKET",1))
return(PACKET);
else return(UNIMPLEMENTED);
case 'R':
if(!strncmp(cmd,"RESTART",7))
return(RESTART);
else return(UNIMPLEMENTED);
case 'S':
if(!strncmp(cmd,"STATUS",6))
return(STATUS);
else return(UNIMPLEMENTED);
case 'T':
if(!strncmp(cmd,"TERMINATE",9))
return(TERMINATE);
else return(UNIMPLEMENTED);
#ifndef PSRV_READ_ONLY
case 'U':
if(!strncmp(cmd,"UPDATE",6))
return(UPDATE);
else return(UNIMPLEMENTED);
#endif
case 'V':
if(!strncmp(cmd,"VERSION",7))
return(VERSION);
else return(UNIMPLEMENTED);
default:
return(UNIMPLEMENTED);
}
}
SIGNAL_RET_TYPE term_sig()
{
char qlstring[30];
if(pQlen > 0) sprintf(qlstring," [%d pending]",pQlen);
else *qlstring = '\0';
plog(L_STATUS,NULL,NULL,"Server killed (terminate signal received)%s",qlstring,0);
log_stats();
exit(0);
}
SIGNAL_RET_TYPE trap_error(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
{
char estring[400];
if(pQlen > 0) sprintf(estring," [%d pending]",pQlen);
else *estring = '\0';
plog(L_FAILURE,NULL,NULL,"Failure - Recovering from error at address 0x%x (%d,%d)%s",scp->sc_pc,sig,code,estring,0);
#ifdef DEBUG
plog(L_DIR_ERR,NULL,NULL,"Last request was: %s",last_request,0);
sprintf(estring,"Signal(%d,%d) at 0x%x\n%.300s", sig, code,
scp->sc_pc, last_request);
#else
sprintf(estring,"Signal(%d,%d) at 0x%x", sig, code, scp->sc_pc);
#endif DEBUG
restart_server(++fault_count,estring);
exit(1);
}
/*
* restart server restarts the server by calling exec. Before
* restarting, it logs the current statisitcs which would otherwise
* be lost.
*/
restart_server(fcount,estring)
int fcount; /* Failure count */
char *estring; /* Error string */
{
char dirsrv_b[MAXPATHLEN];
char fault_flag[30];
char error_flag[500];
int f;
/* Log statistics before we forget them on restart */
log_stats();
/* Close all files except stdin, stdout, and stderr */
/* which should still be /dev/null, and in_port */
/* which we might not be able to reopen */
close_plog();
for (f = 3; f < OPEN_MAX; f++) {
if(f != in_port) (void) close(f);
}
sprintf(dirsrv_b,"%s/dirsrv",P_BINARIES);
if(estring) sprintf(error_flag,"-E%-0.497s",estring);
if(fcount) sprintf(fault_flag,"-F%d",fcount);
/* Reinstate the signal that caused the fault */
sigsetmask(0);
/* Restart the server specifying the appropriate flags */
if((fcount == 0) && !estring)
execl(dirsrv_b,"dirsrv",in_parg,root,shadow,pfsdat,aftpdir,
afsdir,hostname,0);
else if((fcount != 0) && estring)
execl(dirsrv_b,"dirsrv",in_parg,fault_flag,error_flag,root,shadow,
pfsdat,aftpdir,afsdir,hostname,0);
else execl(dirsrv_b,"dirsrv",in_parg,(fcount ? fault_flag : error_flag),
root,shadow,pfsdat,aftpdir,afsdir,hostname,0);
/* If we get here, the exec failed */
plog(L_FAILURE,NULL,NULL,"***Failure - Couldn't restart server - exiting***",0);
exit(1);
}
/*
* setup_disc
*
* disconnect all descriptors, remove ourself from the process
* group that spawned us and set signal handlers.
*/
setup_disc()
{
int s;
for (s = 0; s < 3; s++) {
(void) close(s);
}
(void) open("/dev/null", 0, 0);
(void) dup2(0, 1);
(void) dup2(0, 2);
#ifdef SETSID
setsid();
#else
s = open("/dev/tty", 2, 0);
if (s >= 0) {
ioctl(s, TIOCNOTTY, (struct sgttyb *) 0);
(void) close(s);
}
#endif
(void) chdir(P_RUNDIR);
signal(SIGHUP,term_sig);
signal(SIGINT,term_sig);
signal(SIGTERM,term_sig);
signal(SIGQUIT,term_sig);
signal(SIGILL,trap_error);
signal(SIGIOT,trap_error);
signal(SIGEMT,trap_error);
signal(SIGFPE,trap_error);
signal(SIGBUS,trap_error);
signal(SIGSEGV,trap_error);
signal(SIGSYS,trap_error);
return;
}
static
log_stats()
{
plog(L_STATS,NULL,NULL,"Stats: %d List, %d GOI, %d LACL",
list_count,goi_count,lacl_count,0);
plog(L_STATS,NULL,NULL," %d CL, %d CD, %d CO, %d DL",
crlnk_count,crdir_count,crobj_count,dellnk_count,0);
plog(L_STATS,NULL,NULL," %d ML, %d EOI, %d MACL, %d Upd",
modl_count,eoi_count,macl_count,upddir_count,0);
if(oldform_count) plog(L_STATS,NULL,NULL," %d Total, %d Old format",
req_count, oldform_count, 0);
else plog(L_STATS,NULL,NULL," %d Total", req_count,0);
}
static
check_path(path)
char *path;
{
if(*db_prefix && (sindex(path,db_prefix) == path)) return(TRUE);
#ifdef NODOTDOT
if(wcmatch(path,"*..*")) return(FALSE);
#endif
if(sindex(path,pfsdat) == path) return(TRUE);
if(*root && (sindex(path,root) == path)) return(TRUE);
if(*aftpdir && (sindex(path,aftpdir) == path)) return(TRUE);
if(*afsdir && (sindex(path,afsdir) == path)) return(TRUE);
return(FALSE);
}